package com.levy.contronller.jvm.classLoader;


import cn.hutool.core.io.FileUtil;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Driver;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;

/**
 * 当前类加载器(current classLoader)
 *
 * 每个类都会使用自己的类加载器来加载其他类，如果classX引用了ClassY，那么ClassX的类加载器会去加载classY
 * （前提是ClassY尚为被加载）
 *
 * 线程上下文加载器（Context ClassLoader）
 * context classloader 是从1.2引入的，类Thread中的getcontextclassloader()与setcontextclassloader(classloader cl)
 * 用来获得和设置上下文加载器
 *
 * 如果没有通过setContextClassLoader(ClassLoader cl)进行设置的话，线程将集成父线程的上下文加载器。
 * JAVA应用运行时的初始化线程的上下文加载器是AppClassLoader，在线程中运行的代码可以通过该类加载器来加载类和资源。
 *
 * 线程上下文类加载器的重要性
 *
 * SPI（Service Provider Interface）
 * 父ClassLoader可以使用当前线程Thread.currentThread().getcontextClassLoader()所指定的classLoader所加载的的类
 * 这就改变了父ClassLoader不能使用子ClassLoader或是其他没有直接父子关系的ClassLoader加载类的情况，即改变了双亲委托模型。
 *
 * 线程上下文加载器就是当前的CurrentClassLoader
 *
 * 在双亲委托模型下，类的加载是由下至上的，即下层的类加载器会委托上层进行加载。但是对于SPI来说，有些接口是JAVA核心库所提供的，而JAVA核心库是由启动类架子啊其来加载的，
 * 而这些接口的类却来源于不通的JAr包（厂商提供），JAVA的启动类加载器是不会加载其他来源的JAR包，这样传统的委托模型就无法满足SPIder要求，
 * 而通过给当前线程设置上下文的权限，就可以自由设置上下文加载其来实现对于接口实现类的数量
 *
 */
public class MyTest25 {

    /*
        线程上下文类加载器的一般使用模式（获取 - 使用 - 还原）

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        try {
            Thread.currentThread().setContextClassLoader(targetTccl);
            myMethod();
        }finally {
            Thread.currentThread().setContextClassLoader(classLoader);
        }

        myMythod里调用了Thread.currentThread().getContextClassLoader(),获取当前线程的上下文类加载器做业务逻辑的处理
        如果一个类由加载器A记载，那么这个类的依赖类也是由相同的类加载器加载的（如果该依赖类之前没有被加载过的话）
        ContextClassLoader就是为了破坏JAVA的类加载委托机制

        当高层提供了统一的接口让底层去实现，同时又要在高层加载（或实例化）底层的类时，就必须要通过线程上下文类加载器来帮助高层的ClassLoader找到并加载该类


     */


    public static void main(String[] args) {

        System.out.println(Thread.currentThread().getContextClassLoader());
        System.out.println(Thread.class.getClassLoader());


        ServiceLoader<Driver> load = ServiceLoader.load(Driver.class);
        Iterator<Driver> iterator = load.iterator();
        while (iterator.hasNext()){
            Driver driver = iterator.next();
            System.out.println("driver: "+driver.getClass()+",loader: "+driver.getClass().getClassLoader());
        }

        System.out.println("当前线程的上下文加载器: "+Thread.currentThread().getContextClassLoader());
        System.out.println("serviceLoader的类加载器: "+ServiceLoader.class.getClassLoader());
    }
}
